#pragma once

#include "cpo.h"
#include "cpo_implementations.h"
#include "io.h"

namespace serializer
{

// 更直观的序列化自由函数包装
// 用途: 为用户提供非 CPO 的便利入口, 内部仍走统一的 CPO 调度逻辑
// 参数:
//  - writer: 写入器, 必须满足 writer 概念
//  - value: 要序列化的对象
//  - options: 序列化选项, 必须满足 serialization_options 概念
// 返回值: 无
// 异常: 由底层写入器或具体类型的序列化实现抛出异常; 当无可用的序列化路径时可能导致编译期错误
template <typename Writer,
          typename T,
          typename Options,
          typename std::enable_if<writer<Writer> && serialization_options<Options>, int>::type = 0>
constexpr void
serialize(Writer & writer,
          const T & value,
          const Options & options) noexcept(noexcept(serialize_cpo(writer, value, options)))
{
    if (options.get_byte_order() == ::serializer::byte_order::native)
    {
        throw std::invalid_argument("bare-payload serialize forbids byte_order::native; choose "
                                    "little_endian or big_endian");
    }
    serialize_cpo(writer, value, options);
}

// 更直观的反序列化自由函数包装（显式类型版本）
// 用途: 为用户提供非 CPO 的便利入口, 通过显式模板参数指定目标类型 T
// 参数:
//  - reader: 读取器, 必须满足 reader 概念
//  - options: 序列化选项, 必须满足 serialization_options 概念
// 返回值: 目标类型 T 的对象
// 异常: 由底层读取器或具体类型的反序列化实现抛出异常; 当无可用的反序列化路径时可能导致编译期错误
template <typename T,
          typename Reader,
          typename Options,
          typename std::enable_if<reader<Reader> && serialization_options<Options>, int>::type = 0>
constexpr T
deserialize(Reader & reader,
            const Options & options) noexcept(noexcept(deserialize_cpo.template
                                                       operator()<T>(reader, options)))
{
    if (options.get_byte_order() == ::serializer::byte_order::native)
    {
        throw std::invalid_argument("bare-payload deserialize forbids byte_order::native; choose "
                                    "little_endian or big_endian");
    }
    return deserialize_cpo.template operator()<T>(reader, options);
}

// 提供一个反序列化代理类型，用于支持从赋值语境自动推导目标类型
// 通过隐式转换运算符在赋值或初始化时调用统一的 CPO 分发进行反序列化
template <typename Reader, typename Options>
struct DeserializationProxy
{
    Reader * reader;
    const Options * options;

    template <typename T>
    constexpr operator T() const
        noexcept(noexcept(deserialize_cpo.template operator()<T>(*reader, *options)))
    {
        return deserialize_cpo.template operator()<T>(*reader, *options);
    }
};

// 反序列化自由函数（自动类型推导版本）
template <typename Reader,
          typename Options,
          typename std::enable_if<reader<Reader> && serialization_options<Options>, int>::type = 0>
constexpr auto
deserialize(Reader & reader, const Options & options) noexcept
{
    if (options.get_byte_order() == ::serializer::byte_order::native)
    {
        throw std::invalid_argument("bare-payload deserialize forbids byte_order::native; choose "
                                    "little_endian or big_endian");
    }
    return DeserializationProxy<Reader, Options>{&reader, &options};
}

// 写入完整流（含 SRLZ 头部）的自由函数包装
template <typename Writer,
          typename T,
          typename Options,
          typename std::enable_if<writer<Writer> && serialization_options<Options>, int>::type = 0>
constexpr void
serialize_stream(Writer & writer, const T & value, const Options & options) noexcept(
    noexcept(::serializer::write_stream(writer, value, options)))
{
    ::serializer::write_stream(writer, value, options);
}

// 读取完整流（含 SRLZ 头部）的自由函数包装
template <typename T,
          typename Reader,
          typename Options,
          typename std::enable_if<reader<Reader> && serialization_options<Options>, int>::type = 0>
constexpr T
deserialize_stream(Reader & reader, const Options & options) noexcept(
    noexcept(::serializer::read_stream<T>(reader, options)))
{
    return ::serializer::read_stream<T>(reader, options);
}

} // namespace serializer